package com.jml.socketIo;

import org.junit.Test;

import java.net.InetSocketAddress;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.*;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Date;
import java.util.Set;

public class SocketTest {
    @Test
    public void rewind() {
        ByteBuffer byteBuffer = ByteBuffer.allocate(15);
        byteBuffer.put("12345678".getBytes());
        byteBuffer.flip();
        boolean b = byteBuffer.hasRemaining();
        System.out.println(byteBuffer.get());
        System.out.println(byteBuffer.get());
        System.out.println(byteBuffer.get());
        byteBuffer.mark();
        //System.out.println(byteBuffer.remaining());
        //byteBuffer.flip();
        //System.out.println(byteBuffer.rewind());
        System.out.println(byteBuffer.get());
        System.out.println(byteBuffer.get());
        System.out.println(byteBuffer.get());
        Buffer reset = byteBuffer.reset();
        System.out.println(byteBuffer.remaining());
        System.out.println();

    }

    @Test
    public void fun1() throws Exception {
        //创建一个通道
        //第一个是代表文件路径，第二个是针对文件的操作
        FileChannel inChanner = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
        FileChannel outChanner = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE_NEW);
        //只读模式，从0开始到通道的全部
        MappedByteBuffer inMappedBuff = inChanner.map(FileChannel.MapMode.READ_ONLY, 0, inChanner.size());
        MappedByteBuffer outMappedBuff = outChanner.map(FileChannel.MapMode.READ_WRITE, 0, inChanner.size());
        //直接对缓冲区进行数据读写操作
        byte[] bst = new byte[inMappedBuff.limit()];
        inMappedBuff.get(bst);
        outMappedBuff.put(bst);
        inChanner.close();
        outChanner.close();
    }

    @Test
    public void fun5() throws CharacterCodingException {
        //指定编码方式
        Charset cs1 = Charset.forName("UTF-8");
        //获取UTF-8编码器
        CharsetEncoder charsetEncoder = cs1.newEncoder();
        //获取UTF-8解码器
        CharsetDecoder charsetDecoder = cs1.newDecoder();

        CharBuffer charBuffer = CharBuffer.allocate(1024);
        charBuffer.put("编码和解码!");
        charBuffer.flip();
        //编码
        ByteBuffer byteBuffer = charsetEncoder.encode(charBuffer);

        for (int i = 0; i < 12; i++) {
            System.out.println(byteBuffer.get());
        }
        //解码
        byteBuffer.flip();
        CharBuffer charBuffer1 = charsetDecoder.decode(byteBuffer);
        System.out.println(charBuffer1.toString());
    }

    @Test
    public void servers() throws Exception {
        //获取通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //切换成非阻塞模式
        serverSocketChannel.configureBlocking(false);
        //绑定连接
        serverSocketChannel.bind(new InetSocketAddress(9898));
        //获取选择器
        Selector selector = Selector.open();
        //将通道注册到选择器上,指定监听事件
        //当调用register将通道注册选择器时，选择器对通道的监听事件，需要第二个参数
        //SelectionKey.OP_READ      读
        //SelectionKey.OP_WRITE     写
        //SelectionKey.OP_CONNECT   连接
        //SelectionKey.OP_ACCEPT    接收
        //如果注册时候不止监听一个事件，则可以使用“或”运算符
        //SelectionKey.OP_READ|SelectionKey.OP_WRITE
        SelectionKey register = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);//注册接收模式
        //轮训式的获取选择器上已经准备就绪的事件
        while(selector.select()>0){
            //大于0表示已经有准备好的事件了，获取事件
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            for (SelectionKey selectKeys:selectionKeys){
                //判断具体是什么事件准备就绪
                if(selectKeys.isAcceptable()){
                    //是否是接收事件准备就绪，并且拿到客户端的连接
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    //将客户端连接切换为非阻塞模式
                    socketChannel.configureBlocking(false);
                    //将该通道注册到选择器上,读取数据，所以是读数据模式SelectionKey.OP_RED
                    socketChannel.register(selector,SelectionKey.OP_READ);
                    //selectKeys用完后应该取消掉，其实就是从列表中移出，否则这个selectkey永远有效
                    selectionKeys.remove(selectKeys);
                }else if(selectKeys.isReadable()){
                    //判断是否是读就绪状态准备完成,获取读就绪状态通道
                    SocketChannel socketChannel = (SocketChannel) selectKeys.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    int len =0;
                    while((len=socketChannel.read(byteBuffer))>0){
                        byteBuffer.flip();
                        System.out.println(new String(byteBuffer.array(),0,len));
                        byteBuffer.clear();
                    }
                    //selectKeys用完后应该取消掉，其实就是从列表中移出，否则这个selectkey永远有效
                    selectionKeys.remove(selectKeys);
                }

            }
        }
    }

    @Test
    public void clients () throws Exception {
        //获取通道
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
        //切换成非阻塞模式
        socketChannel.configureBlocking(false);
        //分配指定大小缓冲区域
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        //发送数据给服务端
        byteBuffer.put(new Date().toString().getBytes());
        byteBuffer.flip();
        //write之前需要flip
        socketChannel.write(byteBuffer);
        byteBuffer.clear();
        //关闭通道
        socketChannel.close();
        System.out.println("the end...................");
    }
}
